<template>
    <div class="body">
        <div style="font-size: 30px">状态：{{ state }}</div>
        <div  style="font-size: 24px;margin: 0 auto">
            <el-link type="primary" href="https://gitee.com/LLLLLLin/openharmony_commit" style="margin-right: 10px" slot="reference">代码仓库地址</el-link>
            <el-link type="primary" href="https://gitee.com/api/v5/swagger#/getV5ReposOwnerRepoStargazers?ex=no" style="margin-right: 10px" slot="reference">gitee文档</el-link>

        </div>
        <div class="flex-between" style="font-size: 24px">
            配置
        </div>
        <div class="flex-between">
            <el-popover
                placement="top-start"
                title="token获取"
                width="200"
                trigger="hover"
                content="访问https://gitee.com/api/v5/swagger#/getV5OrgsOrgRepos 后,点击右上角申请授权，授权后access_token一栏即可看到">
                <el-link type="primary" style="margin-right: 10px" slot="reference">token:</el-link>
            </el-popover>

            <el-input v-model="token" placeholder="请输入token" style="width: 200px;flex-grow: 1"></el-input>
            <div style="margin: 0 10px">时间：</div>
            <el-date-picker
                value-format="yyyy-MM-dd"
                v-model="date"
                type="daterange"
                range-separator="至"
                start-placeholder="开始日期"
                end-placeholder="结束日期">
            </el-date-picker>
        </div>
        <div class="flex-between">
            <div>请选择org组织（多选，右侧可新增组织）:</div>
            <el-input placeholder="新增组织" v-model="orgInput" style="width: 200px">
                <el-button slot="append" icon="el-icon-plus" @click="addOrg"></el-button>
            </el-input>
        </div>
        <div class="flex-between">
            <el-checkbox-group v-model="selectedOrg">
                <el-checkbox-button v-for="org in orgOptions" :label="org" :key="org">{{ org }}</el-checkbox-button>
            </el-checkbox-group>
            <el-button type="warning" style="margin-left: 10px" @click="clearOrg">重置</el-button>
        </div>
        <div class="flex-row">
            <div style="margin-right: 20px">请选择仓库类型: </div>
            <el-select v-model="orgType" placeholder="请选择">
                <el-option
                    v-for="item in orgTypeOptions"
                    :key="item"
                    :label="item"
                    :value="item">
                </el-option>
            </el-select>
        </div>
        <el-divider></el-divider>
        <div class="flex-between" style="font-size: 24px">
            操作
        </div>
        <div class="flex-row">
            <el-button type="primary" @click="getRepo" :disabled="isLoadingRepo"> 1.根据组织获取仓库: {{ repos.length }}
            </el-button>
            <el-button type="primary" @click="getCommits" :disabled="isLoadingCommit">
                2. 获取仓库下所有提交:{{ commitList.length }}
            </el-button>
            <el-input
                style="margin: 0 10px"
                placeholder="过滤邮箱"
                prefix-icon="el-icon-search"
                v-model="filterEmail">
            </el-input>
            <el-button type="primary" @click="getFilterCommits" :disabled="isLoadingCommit">
                3. 获取过滤后的提交:{{ filterCommits.length }}
            </el-button>
        </div>
        <div class="flex-row">
            <el-popover
                placement="top-start"
                title="并发限制说明"
                width="200"
                trigger="hover"
                content="由于修改行数接口并未直接暴露出来，且获取1个commit需要一次请求，若不作限制过于频繁的请求会被服务器拒绝服务">
                <el-link type="primary" slot="reference">最大请求数:</el-link>
            </el-popover>
            <el-input-number v-model="maxQuest" :min="1" :max="2000" label="最大请求数"
                             style="margin:0 10px"></el-input-number>
            <el-button type="warning" @click="getStats" :disabled="isLoadingStat">(可选)获取每个commit增减数(很慢):{{ statsCount }}</el-button>
            <el-button type="warning" @click="getStatsByFilter" :disabled="isLoadingStat">(可选)获取每个过滤commit增减数(很慢):{{ statsCount }}
            </el-button>
            <el-button type="success" icon="el-icon-download" style="margin:0 10px" @click="exportExcel(commitList,'所有commit数据')">导出EXCEL</el-button>
            <el-button type="success" icon="el-icon-download" style="margin:0 10px" @click="exportExcelByGroup">分页导出EXCEL</el-button>
        </div>
        <div class="flex-row">
            <el-button type="success" icon="el-icon-download" style="margin:0 10px" @click="exportExcel(filterCommits,'过滤后commit数据')">导出过滤邮箱后EXCEL</el-button>
        </div>
    </div>
</template>

<script>

import export_json_to_excel from "../excel/Export2Excel";

import FileSaver from 'file-saver';
import * as XLSX from 'xlsx'

export default {
    name: 'OHAndSig',
    data() {
        return {
            token: '0fd1e29a051ab8f564ca7486ba5fb5cc',
            selectedOrg: ['openharmony'],
            orgTypeOptions: ["all","public","private"],
            orgOptions: ['openharmony', 'OpenHarmony-SIG', 'OpenHarmony-TPC'],
            orgInput: '',
            orgType: 'public',
            date: [],
            repos: [],
            isLoadingRepo: false,
            commitList: [],
            isLoadingCommit: false,
            state: '等待中',
            statsCount: 0,// 已添加修改行数字段的commit数量
            maxQuest: 200,// 请求修改行数时，最大请求数
            isLoadingStat: false,
            fields: {
                org: 'org',
                repo: 'repo',
                commit_url: 'commitUrl',
                html_url: 'htmlUrl',
                author_name: 'authorName',
                author_email: 'authorEmail',
                author_date: 'authorDate',
                committer_name: 'committerName',
                committer_email: 'committerEmail',
                committer_date: 'committerDate',
                committer_message: 'committerMessage',
                additions: 'additions',
                deletions: 'deletions',
                total: 'total',
            },
            filterEmail:'',
            filterCommits:[]
        }
    },
    mounted() {
        this.initAxios()
    },
    methods: {
        initAxios() {
            // 设置跨域请求头
            this.axios.defaults.headers.common['Access-Control-Allow-Origin'] = "*"
            this.axios.interceptors.response.use(
                response => {
                    // 如果返回的状态码为200，说明接口请求成功，可以正常拿到数据
                    // 否则的话抛出错误
                    if (response && response.status === 200) {
                        return Promise.resolve(response);
                    } else {
                        return Promise.reject(response);
                    }
                },

                error => {
                    let msg = ''
                    if (error &&error.status && error.response.status) {
                        msg = error.response.status
                    }
                    this.$message.error('请求出错，点击F12进入控制台查看详情：' + msg)
                    console.error(error)
                }
            );
        },
        addOrg() {
            this.orgOptions.push(this.orgInput)
        },
        clearOrg() {
            this.orgOptions = ['openharmony', 'OpenHarmony-SIG', 'OpenHarmony-TPC']
        },
        async getRepo() {
            try {
                this.isLoadingRepo = true
                this.repos = []
                for (let i = 0; i < this.selectedOrg.length; i++) {
                    let org = this.selectedOrg[i]
                    await this.getRepoByOrg(org)
                }
                this.state = 'repo 获取完毕'
            } catch (e) {
                this.state = 'repo 获取失败 F12控制台查看错误'
                console.error(e)
            } finally {
                this.isLoadingRepo = false
            }
        },
        async getRepoByOrg(org) {
            // 获取openharmony下public仓库中
            this.state = '获取openharmony下public仓库中'
            let page = 0
            let totalPage = 0
            const count = 100
            try {
                do {
                    page++
                    let response = await this.axios.get(`https://gitee.com/api/v5/orgs/${org}/repos?access_token=${this.token}&type=${this.orgType}&page=${page}&per_page=${count}`)
                    if (!totalPage) {
                        totalPage = response.headers.total_page
                    }
                    response.data.forEach(item => {
                        this.repos.push({org: org, path: item.path})
                    })

                } while (page < totalPage)
            } catch (e) {
                this.$message.error('获取仓库失败F12控制台查看详情')
                console.error('获取仓库失败')
                console.error(e)
            }
            console.log(`获取${org}所有public仓库完毕`)
            console.log('repos：')
            console.log(this.repos)

        },
        getCommits() {
            if (this.date.length != 2) {
                this.$message.error('请选择时间')
                return
            }
            this.$notify({
                title: '成功',
                message: '开始获取所有提交，为加快获取速度，需自行关注按钮中的提交数是否不再增加了，若有报错注意在F12控制台中进行查看是否可忽略',
                type: 'success'
            });
            let since = this.date[0]
            let end = this.date[1]
            try {
                this.isLoadingCommit = true
                this.commitList = []
                for (let i = 0; i < this.repos.length; i++) {
                    let repo = this.repos[i].path
                    let org = this.repos[i].org
                    let page = 1
                    const maxPageCount = 100
                    this.axios.get(`https://gitee.com/api/v5/repos/${org}/${repo}/commits?access_token=${this.token}&since=${since}&until=${end}&page=${page}&per_page=${maxPageCount}`)
                        .then(async response1 => {
                            if (!response1 || !response1.data){
                                console.warn(response1)
                                return
                            }
                            response1.data.map(item => {
                                this.pushCommitList(org,repo,item)
                            })
                            while (response1.data.length >= maxPageCount) {
                                page++
                                let url = `https://gitee.com/api/v5/repos/${org}/${repo}/commits?access_token=${this.token}&since=${since}&until=${end}&page=${page}&per_page=${maxPageCount}`
                                response1 = await this.axios.get(url)
                                response1.data.map(item => {
                                    this.pushCommitList(org,repo,item)
                                })
                                // console.log('第' + page + '页：' + response1.data.length + ' ' + url)
                            }
                        })
                }

            } catch (e) {
                this.state = 'getCommits 失败'
                console.error(e)

            } finally {
                this.isLoadingCommit = false
            }
        },
        pushCommitList(org,repo,item){
            // 存在author为null情况
            let authorUrl = ""
            if (!item.author || !item.author.html_url){
                authorUrl = ""
            }else {
                authorUrl = item.author.html_url
            }
            let obj = {
                org: org,
                repo: repo,
                htmlUrl: item.html_url,
                commitUrl: item.url,
                authorName: item.commit.author.name,
                authorEmail: item.commit.author.email,
                authorDate: item.commit.author.date,
                authorUrl: authorUrl,
                committerName: item.commit.committer.name,
                committerEmail: item.commit.committer.email,
                committerDate: item.commit.committer.date,
                // committerMessage: item.commit.message
            }
            if (item.commit.message.length > 10000){
                let msg = '(数据过长已截取)' + item.commit.message.substring(0,10000) + '(数据过长已截取)'
                obj.committerMessage = msg
            }else {
                obj.committerMessage = item.commit.message
            }
            this.commitList.push(obj)
        },
        async getStats() {
            this.isLoadingStat = true
            this.state = '获取修改代码行数中'
            this.statsCount = 0
            while (this.statsCount < this.commitList.length) {
                let requests = []
                for (let i = this.statsCount; i < this.statsCount + this.maxQuest; i++) {
                    if (i >= this.commitList.length) {
                        break
                    }
                    let item = this.commitList[i]
                    if (!item || !item.commitUrl) {
                        console.warn(`第${i}条获取修改行数出错`, item)
                        continue
                    }
                    requests.push(this.axios.get(item.commitUrl + '?access_token=' + this.token, {
                        data: i
                    }))
                }
                try {
                    let responseList = await this.axios.all(requests)
                    responseList.forEach(res => {
                        let item = this.commitList[res.config.data]
                        item.additions = res.data.stats.additions
                        item.deletions = res.data.stats.deletions
                        item.total = res.data.stats.total
                    })
                    this.statsCount += this.maxQuest
                    if (this.statsCount > this.commitList.length) {
                        this.statsCount = this.commitList.length
                    }
                    this.state = `成功获取到第${this.statsCount}条`
                } catch (e) {
                    this.state = '获取修改行数数据错误，详情进入F12查看'
                    this.$message.error('获取修改行数数据错误，详情进入F12查看')
                    console.error(e)
                }
            }
            this.isLoadingStat = false
        },
        async getStatsByFilter() {
            this.isLoadingStat = true
            this.state = '获取修改代码行数中'
            this.statsCount = 0
            while (this.statsCount < this.filterCommits.length) {
                let requests = []
                for (let i = this.statsCount; i < this.statsCount + this.maxQuest; i++) {
                    if (i >= this.filterCommits.length) {
                        break
                    }
                    let item = this.filterCommits[i]
                    if (!item || !item.commitUrl) {
                        console.warn(`第${i}条获取修改行数出错`, item)
                        continue
                    }
                    requests.push(this.axios.get(item.commitUrl + '?access_token=' + this.token, {
                        data: i
                    }))
                }
                try {
                    let responseList = await this.axios.all(requests)
                    responseList.forEach(res => {
                        let item = this.filterCommits[res.config.data]
                        item.additions = res.data.stats.additions
                        item.deletions = res.data.stats.deletions
                        item.total = res.data.stats.total
                    })
                    this.statsCount += this.maxQuest
                    if (this.statsCount > this.filterCommits.length) {
                        this.statsCount = this.filterCommits.length
                    }
                    this.state = `成功获取到第${this.statsCount}条`
                } catch (e) {
                    this.state = '获取修改行数数据错误，详情进入F12查看'
                    this.$message.error('获取修改行数数据错误，详情进入F12查看')
                    console.error(e)
                }
            }
            this.isLoadingStat = false
        },
        getFilterCommits(){
            if (!this.filterEmail || this.filterEmail.length == 0){
                this.$message.warning("请输入邮箱")
                return
            }
            let email = this.filterEmail.toLowerCase()
            this.filterCommits = this.commitList.filter(item=>{
                if (item.committerEmail.toLowerCase() == 'noreply@gitee.com'){
                    return item.authorEmail.toLowerCase().includes(email)
                }else {
                    return item.committerEmail.toLowerCase().includes(email)
                }
            })
        },
        //导出的方法
        exportExcel(dataList,title) {
            const tHeader = ["org" , "repo" , "htmlUrl" , "commitUrl" , "authorName" , "authorEmail" , "authorDate" ,"authorUrl" , "committerName" , "committerEmail" , "committerDate" , "committerMessage","additions","deletions","total"]
            // 上面设置Excel的表格第一行的标题
            // const filterVal = ["operationName", "operationType", "operationDate",'operationMsg'];
            const filterVal = ["org" , "repo" , "htmlUrl" , "commitUrl" , "authorName" , "authorEmail" , "authorDate" ,"authorUrl" , "committerName" , "committerEmail" , "committerDate" , "committerMessage","additions","deletions","total"]
            // 上面的index、nickName、name是tableData里对象的属性
            const list = dataList; //把data里的tableData存到list
            const data = this.formatJson(filterVal, list);
            const name = this.date[0] + '至' + this.date[1] +title
            export_json_to_excel(tHeader, data, name);
        },

        formatJson(filterVal, jsonData) {
            return jsonData.map(v => filterVal.map(j => v[j]));
        },
        exportExcelByGroup(){
            let result = this.commitList
            //获取数据长度，用于后期截取
            var length = result.length;
            var xlsxParam = {
                raw: true
            };
            let workbook = XLSX.utils.book_new();
            //每页放4W条数据，获取满页页数
            var fornum = parseInt(length / 40000);
            //获取剩余数据量
            var remainnum = length % 40000;
            //循环sheet页数开始填充
            for (var i = 0; i < fornum; i++) {
                let sheetdata = XLSX.utils.json_to_sheet(result.slice(0, 40000));
                //添加sheet页
                XLSX.utils.book_append_sheet(workbook, sheetdata, 'sheet' + (i + 1));
                result = result.slice(40000);
            }
            //最后剩余数据
            let last = XLSX.utils.json_to_sheet(result);
            XLSX.utils.book_append_sheet(workbook, last, 'sheet' + (fornum + 1));
            let wbout = XLSX.write(workbook, {
                bookType: 'xlsx',
                bookSST: true,
                type: 'array'
            });
            try {
                const name = this.date[0] + '至' + this.date[1] +'所有commit数据.xlsx'
                FileSaver.saveAs(
                    new Blob([wbout], {
                        type: 'application/octet-stream;charset=utf-8"'
                    }), name);
            } catch (e) {
                if (typeof console !== 'undefined') console.error(e, wbout);
            }
        }
    }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
    font-weight: normal;
}

ul {
    list-style-type: none;
    padding: 0;
}

li {
    display: inline-block;
    margin: 0 10px;
}

a {
    color: #42b983;
}

.flex-row {
    display: flex;
    flex-direction: row;
    align-items: center;
    margin: 10px 0;
    /*flex-wrap: wrap;*/
}

.flex-between {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    margin: 10px 0;
}

.body {
    width: 900px;
    margin: 0 auto;
}
</style>
